struct timer_opts *cur_timer = &timer_none;
-/* These are peridically updated in shared_info, and then copied here. */
-static u32 shadow_tsc_stamp;
-static u64 shadow_system_time;
-static u32 shadow_time_version;
-static struct timeval shadow_tv;
+extern u64 shadow_system_time;
+extern void __get_time_values_from_xen(void);
/* Keep track of last time we did processing/updating of jiffies and xtime. */
-static u64 processed_system_time; /* System time (ns) at last processing. */
+u64 processed_system_time; /* System time (ns) at last processing. */
#define NS_PER_TICK (1000000000ULL/HZ)
EXPORT_SYMBOL(monotonic_clock);
-/*
- * Reads a consistent set of time-base values from Xen, into a shadow data
- * area. Must be called with the xtime_lock held for writing.
- */
-static void __get_time_values_from_xen(void)
-{
- do {
- shadow_time_version = HYPERVISOR_shared_info->time_version2;
- rmb();
- shadow_tv.tv_sec = HYPERVISOR_shared_info->wc_sec;
- shadow_tv.tv_usec = HYPERVISOR_shared_info->wc_usec;
- shadow_tsc_stamp = HYPERVISOR_shared_info->tsc_timestamp.tsc_bits;
- shadow_system_time = HYPERVISOR_shared_info->system_time;
- rmb();
- }
- while ( shadow_time_version != HYPERVISOR_shared_info->time_version1 );
-}
-
/*
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
static inline void do_timer_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
{
- s64 delta;
- unsigned long ticks = 0;
#ifdef CONFIG_X86_IO_APIC
if (timer_ack) {
}
#endif
- __get_time_values_from_xen();
-
- delta = (s64)(shadow_system_time - processed_system_time);
- if (delta < 0) {
- printk("Timer ISR: Time went backwards: %lld\n", delta);
- return;
- }
-
- /* Process elapsed jiffies since last call. */
- while (delta >= NS_PER_TICK) {
- ticks++;
- delta -= NS_PER_TICK;
- processed_system_time += NS_PER_TICK;
-
- if (regs)
- do_timer_interrupt_hook(regs);
- }
+ if (regs)
+ do_timer_interrupt_hook(regs);
#if 0 /* XEN PRIV */
/*
*/
irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
+ s64 delta;
+
/*
* Here we are in the timer irq handler. We just have irqs locally
* disabled but we don't know if the timer_bh is running on the other
*/
write_seqlock(&xtime_lock);
+ __get_time_values_from_xen();
+
+ delta = (s64)(shadow_system_time - processed_system_time);
+ if (delta < 0) {
+ printk("Timer ISR: Time went backwards: %lld\n", delta);
+ goto out;
+ }
+
+ if (delta < NS_PER_TICK)
+ goto out;
+
cur_timer->mark_offset();
do_timer_interrupt(irq, NULL, regs);
+ out:
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
}
#endif
xtime.tv_sec = HYPERVISOR_shared_info->wc_sec;
wall_to_monotonic.tv_sec = -xtime.tv_sec;
- xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
+ xtime.tv_nsec = HYPERVISOR_shared_info->wc_usec * 1000;
wall_to_monotonic.tv_nsec = -xtime.tv_nsec;
cur_timer = select_timer();
extern spinlock_t i8253_lock;
static int use_tsc;
-/* Number of usecs that the last interrupt was delayed */
-static int delay_at_last_interrupt;
-static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */
-static unsigned long last_tsc_high; /* msb 32 bits of Time Stamp Counter */
static unsigned long long monotonic_base;
+static u32 monotonic_offset;
static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED;
/* convert from cycles(64bits) => nanoseconds (64bits)
/* These are peridically updated in shared_info, and then copied here. */
static u32 shadow_tsc_stamp;
-static u64 shadow_system_time;
+u64 shadow_system_time;
static u32 shadow_time_version;
static struct timeval shadow_tv;
+static unsigned int rdtsc_bitshift;
+extern u64 processed_system_time;
+
+#define NS_PER_TICK (1000000000ULL/HZ)
/*
* Reads a consistent set of time-base values from Xen, into a shadow data
* area. Must be called with the xtime_lock held for writing.
*/
-static void __get_time_values_from_xen(void)
+void __get_time_values_from_xen(void)
{
do {
shadow_time_version = HYPERVISOR_shared_info->time_version2;
rdtsc(eax,edx);
/* .. relative to previous jiffy (32 bits is enough) */
- eax -= last_tsc_low; /* tsc_low delta */
+ eax -= (shadow_tsc_stamp << rdtsc_bitshift) & 0xffffffff;
/*
- * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient
- * = (tsc_low delta) * (usecs_per_clock)
- * = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy)
+ * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient
+ * = (tsc_low delta) * (usecs_per_clock)
+ * = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy)
*
* Using a mull instead of a divl saves up to 31 clock cycles
* in the critical path.
- */
+ */
__asm__("mull %2"
:"=a" (eax), "=d" (edx)
"0" (eax));
/* our adjusted time offset in microseconds */
- return delay_at_last_interrupt + edx;
+ return edx;
}
static unsigned long long monotonic_clock_tsc(void)
/* atomically read monotonic base & last_offset */
do {
seq = read_seqbegin(&monotonic_lock);
- last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
+ last_offset = monotonic_offset << rdtsc_bitshift;
base = monotonic_base;
} while (read_seqretry(&monotonic_lock, seq));
static void mark_offset_tsc(void)
{
- unsigned long lost,delay;
- unsigned long delta = last_tsc_low;
-#if 0
- int count;
- int countmp;
- static int count1 = 0;
-#endif
- unsigned long long this_offset, last_offset;
- static int lost_count = 0;
-
- write_seqlock(&monotonic_lock);
- last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
- /*
- * It is important that these two operations happen almost at
- * the same time. We do the RDTSC stuff first, since it's
- * faster. To avoid any inconsistencies, we need interrupts
- * disabled locally.
- */
-
- /*
- * Interrupts are just disabled locally since the timer irq
- * has the SA_INTERRUPT flag set. -arca
- */
-
- /* read Pentium cycle counter */
-
- rdtsc(last_tsc_low, last_tsc_high);
-
-#if 0
- spin_lock(&i8253_lock);
- outb_p(0x00, PIT_MODE); /* latch the count ASAP */
+ s64 delta;
+ unsigned int ticks = 0;
- count = inb_p(PIT_CH0); /* read the latched count */
- count |= inb(PIT_CH0) << 8;
+ write_seqlock(&monotonic_lock);
- /*
- * VIA686a test code... reset the latch if count > max + 1
- * from timer_pit.c - cjb
- */
- if (count > LATCH) {
- outb_p(0x34, PIT_MODE);
- outb_p(LATCH & 0xff, PIT_CH0);
- outb(LATCH >> 8, PIT_CH0);
- count = LATCH - 1;
- }
+ delta = (s64)(shadow_system_time - processed_system_time);
- spin_unlock(&i8253_lock);
-
- if (pit_latch_buggy) {
- /* get center value of last 3 time lutch */
- if ((count2 >= count && count >= count1)
- || (count1 >= count && count >= count2)) {
- count2 = count1; count1 = count;
- } else if ((count1 >= count2 && count2 >= count)
- || (count >= count2 && count2 >= count1)) {
- countmp = count;count = count2;
- count2 = count1;count1 = countmp;
- } else {
- count2 = count1; count1 = count; count = count1;
- }
+ /* Process elapsed jiffies since last call. */
+ while (delta >= NS_PER_TICK) {
+ ticks++;
+ delta -= NS_PER_TICK;
+ processed_system_time += NS_PER_TICK;
}
-#endif
+ jiffies_64 += ticks - 1;
- /* lost tick compensation */
- delta = last_tsc_low - delta;
- {
- register unsigned long eax, edx;
- eax = delta;
- __asm__("mull %2"
- :"=a" (eax), "=d" (edx)
- :"rm" (fast_gettimeoffset_quotient),
- "0" (eax));
- delta = edx;
- }
- delta += delay_at_last_interrupt;
- lost = delta/(1000000/HZ);
- delay = delta%(1000000/HZ);
- if (lost >= 2) {
- jiffies_64 += lost-1;
-
- /* sanity check to ensure we're not always losing ticks */
- if (lost_count++ > 100) {
- printk(KERN_WARNING "Losing too many ticks!\n");
- printk(KERN_WARNING "TSC cannot be used as a timesource. \n");
- printk(KERN_WARNING "Possible reasons for this are:\n");
- printk(KERN_WARNING " You're running with Speedstep,\n");
- printk(KERN_WARNING " You don't have DMA enabled for your hard disk (see hdparm),\n");
- printk(KERN_WARNING " Incorrect TSC synchronization on an SMP system (see dmesg).\n");
- printk(KERN_WARNING "Falling back to a sane timesource now.\n");
-
- clock_fallback();
- }
- /* ... but give the TSC a fair chance */
- if (lost_count > 25)
- cpufreq_delayed_get();
- } else
- lost_count = 0;
/* update the monotonic base value */
- this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
- monotonic_base += cycles_2_ns(this_offset - last_offset);
+ monotonic_base = shadow_system_time;
+ monotonic_offset = shadow_tsc_stamp;
write_sequnlock(&monotonic_lock);
-
-#if 0
- /* calculate delay_at_last_interrupt */
- count = ((LATCH-1) - count) * TICK_SIZE;
- delay_at_last_interrupt = (count + LATCH/2) / LATCH;
-#else
- delay_at_last_interrupt = 0;
-#endif
-
- /* catch corner case where tick rollover occured
- * between tsc and pit reads (as noted when
- * usec delta is > 90% # of usecs/tick)
- */
- if (lost && abs(delay - delay_at_last_interrupt) > (900000/HZ))
- jiffies_64++;
}
static void delay_tsc(unsigned long loops)
static int
time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
- void *data)
+ void *data)
{
struct cpufreq_freqs *freq = data;
"0" (eax), "1" (edx));
}
+ rdtsc_bitshift = HYPERVISOR_shared_info->tsc_timestamp.tsc_bitshift;
+
set_cyc2ns_scale(cpu_khz/1000);
__get_time_values_from_xen();
+ processed_system_time = shadow_system_time;
rdtscll(alarm);